#include "Application.h"

#include <Log/Log.h>
#include <Event/WindowEvent.h>
#include <Layer/SDLImguiLayer/SDLImguiLayer.h>
#include <imgui.h>

namespace Engine2D
{
    Application::Application(ApplicationArgs args)
    {

    }

    Application::~Application()
    {
        m_imguiLayer->OnDetach();
    }

    void Application::Init()
    {
        m_window = CreateEngineWindow(Window_SDL, WindowArgs{"example", 100, 100, 1280, 920});
        m_window->SetEventCallback([this](EventPtr event) { this->OnEvent(event); });
        // m_renderer = CreateRenderer(RendererType::Renderer_SDL);
        Renderer::Instance()->SetWindow(m_window->GetWindow());
        m_imguiLayer = std::make_shared<SDLImguiLayer>();
        SDLContext ctx{m_window->GetWindow(), Renderer::Instance()->GetRenderer()};
        m_imguiLayer->OnAttach((void*)&ctx);
    }

    void Application::Run()
    {
        LOG_DEBUG("{}", "Start EventLoop");
        m_eventLoop.Start([this](EventLoop * loop) {
            m_window->PollEvent();
            Renderer::Instance()->Clear(64, 64, 64);
            for (auto && layer : m_layers) {
                layer->OnUpdate(LayerArgs{loop});
            }
            m_imguiLayer->Begin();
            for (auto && layer : m_layers) {
                layer->OnImGui();
            }
            m_imguiLayer->End();
            Renderer::Instance()->Render();
        });
    }

    void Application::RemoveLayer(Layer const *layer)
    {
        m_layers.erase(std::remove_if(m_layers.begin(), m_layers.end(), [&](std::shared_ptr<Layer> item) {
            return item.get() == layer;
        }), m_layers.end());
    }

    void Application::OnEvent(EventPtr event)
    {
        // LOG_DEBUG(event->Name());
        EventDispatcher dispatcher(event);
        dispatcher.Dispatcher<QuitEvent>([this](EventPtr e) { this->OnClose(e); });
        dispatcher.Dispatcher<WindowEvent>([this](EventPtr e) { this->OnResize(e); });
        for (auto && layer : m_layers) {
            layer->OnEvent(event);
        }
    }

    void Application::OnClose(EventPtr event)
    {
        this->m_eventLoop.ConvertStatus(Status::Stop);
    }

    void Application::OnResize(EventPtr event)
    {
        auto p = dynamic_cast<ResizeEvent*>(event.get());
        if (p) {
            LOG_INFO("Resize Event, size: {} x {}", 
                p->width,
                p->height
            );
        }
    }

} // namespace Engine2D